--[[
-- Author:      feilong
-- DateTime:    2018-04-23 17:19:33
-- Description:

--]]

local socket = require "skynet.socket"
local httpd = require "http.httpd"
local sockethelper = require "http.sockethelper"
local urllib = require "http.url"
local cjson = require "cjson"

---------------------------------------------------------
-- class
---------------------------------------------------------
local Service = class("Service")

function Service:ctor(name)
	--根目录
	local src_path = g.getenv("root")
	local server_name = g.getenv("server_name")
	self.web_root = src_path..server_name.."/view/X-admin/"
	g.contrl = new("agent.contrl")
	g.handler = new("agent.handler")
	self:register()
end

function Service:register()
	g.register('start', handler(self, self.onStart))
	g.register('close', handler(self, self.onClose))
	g.register('accept', handler(self, self.onAccept))

end

function Service:onStart()
	g.handler:onStart()
	return true
end

function Service:onClose()

	return true
end

--接收客户端消息
function Service:onAccept(id, ... )
	socket.start(id)
	-- limit request body size to 8192 (you can pass nil to unlimit)
	local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), nil)
	print("onAccept:",code, url, method, header, body)
	--print(method, header, body )
	if code then
		if code ~= 200 then
			--请求失败
			self:resError(id, code)
			return
		else
			local path, query = urllib.parse(url) --解析url
			--print("parse(url):", path, tostring(query))
			--默认页
			if url == "/" then
				path = "index.html"
			end
			--静态页面
			if self:isStaticFile(path) then
				self:openStaticFile(id,path)
				socket.close(id)
				return
			end
			----------- 需要动态处理的消息-----------
			--local token = header.token
			local cmd = path:match(".*%/(.+)$")
			local param
			if query then
				--解析参数
				param = urllib.parse_query(query) or {}
			end

			if string.upper(method)=='POST' then
				local ok = nil
				ok, param = pcall(cjson.decode,body)
				if not ok then
					print("json decode err:", ok, param)
					--请求失败
					self:resError(id)
					return
				end
				g.log:info("post cmd:",cmd, param)
			else
				g.log:info("get cmd:",cmd, param)
			end

			assert(cmd, "http cmd is null")
			self:dispatchClientMessage(id, cmd, param)
		end
	else
		g.log:err("req err:", code, url, method, body)
		self:resError(id)
		return
	end
	--发生错误
	if url == sockethelper.socket_error then
		g.log:error("socket closed")
	end
	socket.close(id)
end

--派发客户端消息，对返回消息处理
function Service:dispatchClientMessage(id, cmd, ... )
	local header = {}
	header["Content-Type"] = "application/json"
	local res = g.dispatch:dispatchMessage(_, _, cmd, ...)
	-- print("dispatchClientMessage:",id,res)
	if res and next(res) then
		local error_msg = g.error_code:getDes(res.code)
		if error_msg then
			res.msg = error_msg
		end
		self:response(id, 200, cjson.encode(res), header)
		return
	end

	local error_msg = cjson.encode({code=-1, msg="消息无处理"})
	self:response(id, 200, error_msg, header)
end

--回复错误
function Service:resError(id, code)
	local header = {}
	header["Content-Type"] = "application/json"
	local error_msg = cjson.encode({code=-1, msg="消息错误"})
	code = code or 200
	self:response(id, code, error_msg, header)
	socket.close(id)
end

--返回消息给客户端
function Service:response(id, ...)
	local ok, err = httpd.write_response(sockethelper.writefunc(id), ...)
	if not ok then
		-- if err == sockethelper.socket_error , that means socket closed.
		g.log:error(string.format("fd = %d, %s", id, err))
	end
end

-- 是静态网页文件
function Service:isStaticFile(path)
	local suffix = path:match("^.+(%.%a+)$")
	-- print("___suffix__",suffix)
	if not suffix or suffix==".lua" then
		return false
	end
	return true
end

-- 把静态文件返回给客户端
function Service:openStaticFile(id, file_path)
	local file_path = self.web_root..file_path
	local file = io.open(file_path, "rb")
	if not file then
		return self:response(id, 501, "file not exist!")
	end
	local size = file:seek("end")
	local header = {}
	header["Content-Length"] = size
	file:seek("set", 0)
	local data = file:read("*a")
	file:close()
	self:response(id, 200, data, header)
end

return Service
